package com.power.sifa.correction.model.pojo.bo.rule;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.power.sifa.correction.model.Crc_geopoint;
import com.power.sifa.correction.model.Crw_rule_disabled;
import com.power.sifa.correction.model.Crw_rule_zonein;
import com.power.sifa.correction.model.enumeration.St_enable;
import com.power.sifa.correction.model.pojo.bo.CheckRuleRequestBO;
import com.power.sifa.correction.model.pojo.bo.CheckRuleResultBO;
import com.power.sifa.util.GeoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @ClassName ZoomInRule
 * @Author xiongzw
 * @Date 2023/12/10 9:54
 * @Description 入圈规则
 * @Version: 1.0
 **/

@Slf4j
public class ZoneInRuleHandler extends AbstractRuleHandler {

    public ZoneInRuleHandler() {
    }

    /**
     * 入圈规则校验方法
     *
     * @param request             请求对象
     * @param checkRuleResultList 结果对象
     */
    @Override
    public void handleRule(CheckRuleRequestBO request, List<CheckRuleResultBO> checkRuleResultList) {
        log.info("-------入圈规则校验中-------");
        // 查询当前的入圈规则
        List<Crw_rule_zonein> zoneinRules = request.getZoneInRules();
        log.info("-------当前请求的入圈规则数量: {}------- ", zoneinRules.size());
        if (Objects.nonNull(this.getNextRule())) {
            this.getNextRule().handleRule(request, checkRuleResultList);
        }
        // 校验当前的规则
        if (CollectionUtil.isNotEmpty(zoneinRules)) {
            List<String> descibeList = new ArrayList<>();
            for (Crw_rule_zonein zoneInRule : zoneinRules) {
                descibeList = new ArrayList<>();
                log.info("-------入圈规则{}: 开始校验-------" , zoneInRule.getId());
                // 判断规则是否启用
                if (zoneInRule.getStatus().equals(St_enable.YES)) {
                    if (ObjectUtil.isNull(zoneInRule.getGeopoint()) || CollectionUtil.isEmpty(zoneInRule.getGeopoint())) {
                        log.info("-------入圈规则{}: 范围坐标为空，无法校验结束-------" , zoneInRule.getId());
                    }  else if (StringUtils.isEmpty(zoneInRule.getStarthm()) || StringUtils.isEmpty(zoneInRule.getEndhm())) {
                        log.info("-------入圈规则{}: 设置时间范围为空，无法校验结束-------" , zoneInRule.getId());
                    } else {
                        // 判断当前规则是否被屏蔽
                        Boolean isBand = Boolean.FALSE;
                        if (CollectionUtil.isNotEmpty(request.getDisabledRules())) {
                            Set<String> disabledZoneInRuleSet = request.getDisabledRules().stream().map(Crw_rule_disabled::getRuleid).collect(Collectors.toSet());
                            if (CollectionUtil.isNotEmpty(disabledZoneInRuleSet) && disabledZoneInRuleSet.contains(zoneInRule.getId())) {
                               isBand = Boolean.TRUE;
                            }
                        }
                        if (!isBand) {
                            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
                            String recordTimeStr = sdf.format(request.getRectime());
                            DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
                            LocalTime recordDate = LocalTime.parse(recordTimeStr, timeFormatter);
                            LocalTime startTime = LocalTime.parse(zoneInRule.getStarthm(), timeFormatter);
                            LocalTime endTime = LocalTime.parse(zoneInRule.getEndhm(), timeFormatter);
                            // 如果结束时间小于开始时间，则标识跨天
                            Boolean timeResult = Boolean.FALSE;
                            if (endTime.isBefore(startTime)) {
                                // 跨天,出现时间在开始时间到凌晨，和凌晨到结束时间两个区间
                                if ((recordDate.isAfter(startTime) && recordDate.isBefore(LocalTime.MAX)) || (recordDate.isAfter(LocalTime.MIN) && recordDate.isBefore(endTime))) {
                                    timeResult = Boolean.TRUE;
                                }
                            } else {
                                // 未跨天，并且出现时间在设置的时间区间内
                                if (recordDate.isAfter(startTime) && recordDate.isBefore(endTime)) {
                                    timeResult = Boolean.TRUE;
                                }
                            }
                            if (timeResult) {
                                for (Crc_geopoint crc_geopoint : zoneInRule.getGeopoint()) {
                                    if (StringUtils.isNotEmpty(crc_geopoint.getGeopoints())) {
                                        // 获取坐标数组
                                        List<List<Map>> polygonMaps = JSON.parseArray(crc_geopoint.getGeopoints());
                                        List<double[]> polygon = new ArrayList<>();
                                        if (CollectionUtil.isNotEmpty(polygonMaps)) {
                                            List<Map> areaMaps = polygonMaps.get(0);
                                            for (Map areaMap : areaMaps) {
                                                if (ObjectUtil.isNotNull(areaMap.get("lat")) && ObjectUtil.isNotNull(areaMap.get("lng"))) {
                                                    if (areaMap.get("lat") instanceof BigDecimal && areaMap.get("lng") instanceof BigDecimal) {
                                                        double lat = ((BigDecimal) areaMap.get("lat")).doubleValue();
                                                        double lng = ((BigDecimal) areaMap.get("lng")).doubleValue();
                                                        polygon.add(new double[]{lng, lat});
                                                    }
                                                }
                                            }
                                        }
                                        if (ObjectUtil.isNull(request.getLngcamera()) || ObjectUtil.isNull(request.getLatcamera())) {
                                            log.info("-------入圈规则{}: 推送数据坐标为空，无法校验结束-------", zoneInRule.getId());
                                        } else {
                                            log.info("-------入圈规则：{}，坐标范围：{}------", zoneInRule.getId(), crc_geopoint.getGeopoints());
                                            Boolean zoomInResult = GeoUtil.isPointInPolygon(request.getLngcamera().doubleValue(), request.getLatcamera().doubleValue(), polygon);
                                            log.info("-------入圈规则校验结束，结果{}-------", zoomInResult);
                                            if (zoomInResult) {
                                                StringBuffer describeBuff = new StringBuffer();
                                                SimpleDateFormat fmt = new SimpleDateFormat("yyyy年MM月dd日HH时mm分");
                                                String timeStr = ObjectUtil.isNotEmpty(request.getRectime()) ? fmt.format(request.getRectime()) : "";
                                                describeBuff.append("社矫人员：").append(request.getPersonInfo().getName()).append("于：").append(timeStr)
                                                        .append("在地点：").append(request.getAddr()).append("，违反入圈规则：").append(zoneInRule.getName());
                                                descibeList.add(describeBuff.toString());
                                                CheckRuleResultBO checkRuleResult = CheckRuleResultBO.builder().validate(zoomInResult).rectime(request.getRectime()).gaid(request.getId())
                                                        .ruleId(zoneInRule.getId()).ruleName(zoneInRule.getName()).describeList(descibeList).latcamera(request.getLatcamera()).lngcamera(request.getLngcamera())
                                                        .build();
                                                checkRuleResultList.add(checkRuleResult);
                                                break;
                                            } else {
                                                log.info("-------社矫人员{}未违反入圈规则{}-------", request.getPersonInfo().getName(), zoneInRule.getId());
                                            }
                                        }
                                    }
                                }
                            } else {
                                log.info("-------入圈规则{}的时间范围为{}-{}，当前公安数据时间为{}，不在对应范围内，该条规则校验跳过-------", zoneInRule.getId(),zoneInRule.getStarthm(),zoneInRule.getEndhm(), recordTimeStr);
                            }
                        } else {
                            log.info("-------社矫人员{}设置了屏蔽违反入圈规则{}，该条规则校验跳过-------", request.getPersonInfo().getName(), zoneInRule.getId());
                        }
                    }
                } else {
                    log.info("-------入圈规则{}: 无需校验结束-------" , zoneInRule.getId());
                }
            }
        } else {
            log.info("-------入圈规则数量为零: 无需校验结束-------");
        }
    }

}
